/**
 * Copyright (c) 快宝网络 kuaidihelp.com Co., Ltd. All Rights Reserved 禁止外泄以及用于其它的商业用途
 */

import cryptoCfg from './request-config';
import Cookie from 'js-cookie';

// **** 兼容微信 **** //
const mini = null;
/* eslint-disable*/
const getRandomValues = function(array) {
  for (var i = 0, l = array.length; i < l; i++) {
    array[i] = Math.floor(Math.random() * 256);
  }
  return array;
};

let WebAssembly = mini ? WXWebAssembly : window.WebAssembly;
let cacheModule = null;
if (WebAssembly && !WebAssembly.RuntimeError) {
  WebAssembly.RuntimeError = Error;
}

// **** 兼容微信 **** //

var Module = (() => {
  return function(Module) {
    if (cacheModule) {
      // 避免多次触发请求wasm
      return cacheModule.ready;
    }
    Module = Module || {};

    if (!WebAssembly) {
      // 兼容不支持WebAssembly的情况
      return Promise.resolve({
        KbCryptoHelper: {
          buildDigest: () => [],
        },
      });
    }

    var Module = typeof Module != 'undefined' ? Module : {};
    var readyPromiseResolve, readyPromiseReject;
    Module['ready'] = new Promise(function(resolve, reject) {
      readyPromiseResolve = resolve;
      readyPromiseReject = reject;
    });
    var moduleOverrides = Object.assign({}, Module);
    var arguments_ = [];
    var thisProgram = './this.program';
    var quit_ = (status, toThrow) => {
      throw toThrow;
    };
    var ENVIRONMENT_IS_WEB = true;
    var ENVIRONMENT_IS_WORKER = false;
    var scriptDirectory = '';
    function locateFile(path) {
      if (Module['locateFile']) {
        return Module['locateFile'](path, scriptDirectory);
      }
      return scriptDirectory + path;
    }
    var read_, readAsync, readBinary, setWindowTitle;
    var out = Module['print'] || console.log.bind(console);
    var err = Module['printErr'] || console.warn.bind(console);
    Object.assign(Module, moduleOverrides);
    moduleOverrides = null;
    if (Module['arguments']) arguments_ = Module['arguments'];
    if (Module['thisProgram']) thisProgram = Module['thisProgram'];
    if (Module['quit']) quit_ = Module['quit'];
    var wasmBinary;
    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];
    var noExitRuntime = Module['noExitRuntime'] || true;
    if (typeof WebAssembly != 'object') {
      abort('no native wasm support detected');
    }
    var wasmMemory;
    var ABORT = false;
    var EXITSTATUS;
    var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined;
    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
      var endIdx = idx + maxBytesToRead;
      var endPtr = idx;
      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
      }
      var str = '';
      while (idx < endPtr) {
        var u0 = heapOrArray[idx++];
        if (!(u0 & 128)) {
          str += String.fromCharCode(u0);
          continue;
        }
        var u1 = heapOrArray[idx++] & 63;
        if ((u0 & 224) == 192) {
          str += String.fromCharCode(((u0 & 31) << 6) | u1);
          continue;
        }
        var u2 = heapOrArray[idx++] & 63;
        if ((u0 & 240) == 224) {
          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
        } else {
          u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
        }
        if (u0 < 65536) {
          str += String.fromCharCode(u0);
        } else {
          var ch = u0 - 65536;
          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));
        }
      }
      return str;
    }
    function UTF8ToString(ptr, maxBytesToRead) {
      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : '';
    }
    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {
      if (!(maxBytesToWrite > 0)) return 0;
      var startIdx = outIdx;
      var endIdx = outIdx + maxBytesToWrite - 1;
      for (var i = 0; i < str.length; ++i) {
        var u = str.charCodeAt(i);
        if (u >= 55296 && u <= 57343) {
          var u1 = str.charCodeAt(++i);
          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023);
        }
        if (u <= 127) {
          if (outIdx >= endIdx) break;
          heap[outIdx++] = u;
        } else if (u <= 2047) {
          if (outIdx + 1 >= endIdx) break;
          heap[outIdx++] = 192 | (u >> 6);
          heap[outIdx++] = 128 | (u & 63);
        } else if (u <= 65535) {
          if (outIdx + 2 >= endIdx) break;
          heap[outIdx++] = 224 | (u >> 12);
          heap[outIdx++] = 128 | ((u >> 6) & 63);
          heap[outIdx++] = 128 | (u & 63);
        } else {
          if (outIdx + 3 >= endIdx) break;
          heap[outIdx++] = 240 | (u >> 18);
          heap[outIdx++] = 128 | ((u >> 12) & 63);
          heap[outIdx++] = 128 | ((u >> 6) & 63);
          heap[outIdx++] = 128 | (u & 63);
        }
      }
      heap[outIdx] = 0;
      return outIdx - startIdx;
    }
    function stringToUTF8(str, outPtr, maxBytesToWrite) {
      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
    }
    function lengthBytesUTF8(str) {
      var len = 0;
      for (var i = 0; i < str.length; ++i) {
        var c = str.charCodeAt(i);
        if (c <= 127) {
          len++;
        } else if (c <= 2047) {
          len += 2;
        } else if (c >= 55296 && c <= 57343) {
          len += 4;
          ++i;
        } else {
          len += 3;
        }
      }
      return len;
    }
    var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
    function updateGlobalBufferAndViews(buf) {
      buffer = buf;
      Module['HEAP8'] = HEAP8 = new Int8Array(buf);
      Module['HEAP16'] = HEAP16 = new Int16Array(buf);
      Module['HEAP32'] = HEAP32 = new Int32Array(buf);
      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf);
      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf);
      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf);
      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf);
      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf);
    }
    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;
    var wasmTable;
    var __ATPRERUN__ = [];
    var __ATINIT__ = [];
    var __ATPOSTRUN__ = [];
    var runtimeInitialized = false;
    function preRun() {
      if (Module['preRun']) {
        if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
        while (Module['preRun'].length) {
          addOnPreRun(Module['preRun'].shift());
        }
      }
      callRuntimeCallbacks(__ATPRERUN__);
    }
    function initRuntime() {
      runtimeInitialized = true;
      callRuntimeCallbacks(__ATINIT__);
    }
    function postRun() {
      if (Module['postRun']) {
        if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
        while (Module['postRun'].length) {
          addOnPostRun(Module['postRun'].shift());
        }
      }
      callRuntimeCallbacks(__ATPOSTRUN__);
    }
    function addOnPreRun(cb) {
      __ATPRERUN__.unshift(cb);
    }
    function addOnInit(cb) {
      __ATINIT__.unshift(cb);
    }
    function addOnPostRun(cb) {
      __ATPOSTRUN__.unshift(cb);
    }
    var runDependencies = 0;
    var runDependencyWatcher = null;
    var dependenciesFulfilled = null;
    function addRunDependency(id) {
      runDependencies++;
      if (Module['monitorRunDependencies']) {
        Module['monitorRunDependencies'](runDependencies);
      }
    }
    function removeRunDependency(id) {
      runDependencies--;
      if (Module['monitorRunDependencies']) {
        Module['monitorRunDependencies'](runDependencies);
      }
      if (runDependencies == 0) {
        if (runDependencyWatcher !== null) {
          clearInterval(runDependencyWatcher);
          runDependencyWatcher = null;
        }
        if (dependenciesFulfilled) {
          var callback = dependenciesFulfilled;
          dependenciesFulfilled = null;
          callback();
        }
      }
    }
    function abort(what) {
      if (Module['onAbort']) {
        Module['onAbort'](what);
      }
      what = 'Aborted(' + what + ')';
      err(what);
      ABORT = true;
      EXITSTATUS = 1;
      what += '. Build with -sASSERTIONS for more info.';
      var e = new WebAssembly.RuntimeError(what);
      readyPromiseReject(e);
      throw e;
    }
    var dataURIPrefix = 'data:application/octet-stream;base64,';
    function isDataURI(filename) {
      return filename.startsWith(dataURIPrefix);
    }
    var wasmBinaryFile = (cryptoCfg && cryptoCfg.file) || 'crypto.wasm';
    if (Module['locateFile']) {
      if (!isDataURI(wasmBinaryFile)) {
        wasmBinaryFile = locateFile(wasmBinaryFile);
      }
    }
    function getBinary(file) {
      try {
        if (mini) {
          return `/${file}`;
        }
        if (file == wasmBinaryFile && wasmBinary) {
          return new Uint8Array(wasmBinary);
        }
        if (readBinary) {
          return readBinary(file);
        }
        throw 'both async and sync fetching of the wasm failed';
      } catch (err) {
        abort(err);
      }
    }
    function getBinaryPromise() {
      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {
        if (typeof fetch == 'function') {
          return fetch(wasmBinaryFile, { credentials: 'same-origin' })
            .then(function(response) {
              if (!response['ok']) {
                throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
              }
              return response['arrayBuffer']();
            })
            .catch(function() {
              return getBinary(wasmBinaryFile);
            });
        }
      }
      return Promise.resolve().then(function() {
        return getBinary(wasmBinaryFile);
      });
    }
    function createWasm() {
      var info = { a: asmLibraryArg };
      function receiveInstance(instance, module) {
        var exports = instance.exports;
        Module['asm'] = exports;
        wasmMemory = Module['asm']['c'];
        updateGlobalBufferAndViews(wasmMemory.buffer);
        wasmTable = Module['asm']['g'];
        addOnInit(Module['asm']['d']);
        removeRunDependency('wasm-instantiate');
      }
      addRunDependency('wasm-instantiate');
      function receiveInstantiationResult(result) {
        receiveInstance(result['instance']);
      }
      function instantiateArrayBuffer(receiver) {
        return getBinaryPromise()
          .then(function(binary) {
            return WebAssembly.instantiate(binary, info);
          })
          .then(function(instance) {
            return instance;
          })
          .then(receiver, function(reason) {
            err('failed to asynchronously prepare wasm: ' + reason);
            abort(reason);
          });
      }
      function instantiateAsync() {
        if (
          !wasmBinary &&
          typeof WebAssembly.instantiateStreaming == 'function' &&
          !isDataURI(wasmBinaryFile) &&
          typeof fetch == 'function'
        ) {
          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) {
            var result = WebAssembly.instantiateStreaming(response, info);
            return result.then(receiveInstantiationResult, function(reason) {
              console.warn('wasm streaming compile failed: ' + reason);
              console.warn('falling back to ArrayBuffer instantiation');
              return instantiateArrayBuffer(receiveInstantiationResult);
            });
          });
        } else {
          return instantiateArrayBuffer(receiveInstantiationResult);
        }
      }
      if (Module['instantiateWasm']) {
        try {
          var exports = Module['instantiateWasm'](info, receiveInstance);
          return exports;
        } catch (e) {
          err('Module.instantiateWasm callback failed with error: ' + e);
          readyPromiseReject(e);
        }
      }
      instantiateAsync().catch(readyPromiseReject);
      return {};
    }
    function callRuntimeCallbacks(callbacks) {
      while (callbacks.length > 0) {
        callbacks.shift()(Module);
      }
    }
    function _emscripten_memcpy_big(dest, src, num) {
      HEAPU8.copyWithin(dest, src, src + num);
    }
    function getHeapMax() {
      return 2147483648;
    }
    function emscripten_realloc_buffer(size) {
      try {
        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16);
        updateGlobalBufferAndViews(wasmMemory.buffer);
        return 1;
      } catch (e) {}
    }
    function _emscripten_resize_heap(requestedSize) {
      var oldSize = HEAPU8.length;
      requestedSize = requestedSize >>> 0;
      var maxHeapSize = getHeapMax();
      if (requestedSize > maxHeapSize) {
        return false;
      }
      let alignUp = (x, multiple) => x + ((multiple - (x % multiple)) % multiple);
      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
        overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
        var newSize = Math.min(
          maxHeapSize,
          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536),
        );
        var replacement = emscripten_realloc_buffer(newSize);
        if (replacement) {
          return true;
        }
      }
      return false;
    }
    var asmLibraryArg = {
      b: _emscripten_memcpy_big,
      a: _emscripten_resize_heap,
    };
    var asm = createWasm();
    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {
      return (___wasm_call_ctors = Module['___wasm_call_ctors'] = Module['asm']['d']).apply(
        null,
        arguments,
      );
    });
    var _kb_hash_v1 = (Module['_kb_hash_v1'] = function() {
      return (_kb_hash_v1 = Module['_kb_hash_v1'] = Module['asm']['e']).apply(null, arguments);
    });
    var _kb_hash = (Module['_kb_hash'] = function() {
      return (_kb_hash = Module['_kb_hash'] = Module['asm']['f']).apply(null, arguments);
    });
    var _malloc = (Module['_malloc'] = function() {
      return (_malloc = Module['_malloc'] = Module['asm']['h']).apply(null, arguments);
    });
    var _free = (Module['_free'] = function() {
      return (_free = Module['_free'] = Module['asm']['i']).apply(null, arguments);
    });
    var calledRun;
    dependenciesFulfilled = function runCaller() {
      if (!calledRun) run();
      if (!calledRun) dependenciesFulfilled = runCaller;
    };
    function run(args) {
      args = args || arguments_;
      if (runDependencies > 0) {
        return;
      }
      preRun();
      if (runDependencies > 0) {
        return;
      }
      function doRun() {
        if (calledRun) return;
        calledRun = true;
        Module['calledRun'] = true;
        if (ABORT) return;
        initRuntime();
        readyPromiseResolve(Module);
        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']();
        postRun();
      }
      if (Module['setStatus']) {
        Module['setStatus']('Running...');
        setTimeout(function() {
          setTimeout(function() {
            Module['setStatus']('');
          }, 1);
          doRun();
        }, 1);
      } else {
        doRun();
      }
    }
    if (Module['preInit']) {
      if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
      while (Module['preInit'].length > 0) {
        Module['preInit'].pop()();
      }
    }
    run();
    class KbCryptoHelper {
      static makeNonce(length) {
        if (typeof length !== 'number' || length < 1) {
          throw new Error('Invalid length');
        }
        if (mini) {
          // 兼容微信
          return mini
            .arrayBufferToBase64(getRandomValues(new Uint8Array(length * 2)))
            .replace(/[+/]/g, '')
            .substring(0, length);
        }
        if (typeof window.crypto !== 'undefined') {
          return window
            .btoa(String.fromCharCode(...window.crypto.getRandomValues(new Uint8Array(length * 2))))
            .replace(/[+/]/g, '')
            .substring(0, length);
        }
        let result = '';
        for (let i = 0; i < length; i++) {
          result += (Math.random() + 1).toString(16).substring(2);
          if (result.length >= length) {
            return result.substring(0, length);
          }
        }
        return result.substring(0, length);
      }
      static buildDigest(path, appid, sessionId_, nonceData, digestVersion) {
        const sessionId = Cookie.get('session_id') || sessionId_;
        if (
          typeof path !== 'string' ||
          typeof appid !== 'number' ||
          (sessionId && typeof sessionId !== 'string')
        ) {
          throw new Error('Invalid path or appid or sessionId');
        }
        const ts = Date.now();
        const nonce = nonceData || this.makeNonce(16);
        const dataObj = this.createConstChar(ts.toString() + path + (sessionId || ''));
        const nonceObj = this.createConstChar(nonce);
        const digestBuff = this.createDigestOutputBuffer();
        const ok =
          digestVersion === 1
            ? Module._kb_hash_v1(
                appid,
                dataObj.ptr,
                dataObj.byteLen,
                nonceObj.ptr,
                nonceObj.byteLen,
                digestBuff.ptr,
                digestBuff.length,
              )
            : Module._kb_hash(
                appid,
                dataObj.ptr,
                dataObj.byteLen,
                nonceObj.ptr,
                nonceObj.byteLen,
                digestBuff.ptr,
                digestBuff.length,
              );
        dataObj.free();
        nonceObj.free();
        if (!ok) {
          const err = digestBuff.getAndFree();
          throw new Error(`Failed to build digest: ${err}`);
        }
        const digest = digestBuff.getAndFree();
        return [digest, nonce, ts];
      }
      static createConstChar(raw) {
        if (typeof raw !== 'string') {
          throw new Error('Invalid string');
        }
        let finalized = false;
        const len = lengthBytesUTF8(raw);
        const sPtr = Module._malloc(len + 1);
        const written = stringToUTF8(raw, sPtr, len + 1);
        return {
          ptr: sPtr,
          raw: raw,
          byteLen: len,
          length: len,
          written: written,
          free: function() {
            finalized = true;
            return Module._free(sPtr);
          },
          offset: function() {
            return finalized ? null : sPtr;
          },
          get: function() {
            if (finalized) {
              throw new Error('Already finalized');
            }
            return UTF8ToString(sPtr, len);
          },
          getAndFree: function() {
            const result = this.get();
            this.free();
            return result;
          },
        };
      }
      static createDigestOutputBuffer() {
        const len = 66;
        const sPtr = Module._malloc(len + 1);
        let finalized = false;
        return {
          length: len,
          byteLen: len,
          ptr: sPtr,
          get: function() {
            if (finalized) {
              throw new Error('Already finalized');
            }
            return UTF8ToString(sPtr, len);
          },
          free: function() {
            finalized = true;
            return Module._free(sPtr);
          },
          getAndFree: function() {
            const result = this.get();
            this.free();
            return result;
          },
        };
      }
    }

    Module['KbCryptoHelper'] = KbCryptoHelper;

    cacheModule = Module;
    return Module.ready;
  };
})();
const requestCrypto = Module;
export default requestCrypto;
/* eslint-enable */
